package com.codepuzzler;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

public class ForkJoinStringPermutations {
    public static class PermutationsRecursiveTask extends RecursiveTask<List<String>> {
        private char[] str;

        public PermutationsRecursiveTask(char[] str) {
            this.str = str;
        }

        @Override
        public List<String> compute() {
            if (str.length == 1) {
                List<String> single = new ArrayList<String>(1);
                single.add(str[0] + "");
                return single;
            }

            List<String> results = new ArrayList<String>();
            for (char character : str) {
                char[] others = getOtherCharacters(character, str);
                PermutationsRecursiveTask task = new PermutationsRecursiveTask(others);
                task.fork();
                List<String> subResults = task.join();
                for (String subResult : subResults) {
                    results.add(character + subResult);
                }
            }

            return results;
        }

        private char[] getOtherCharacters(char charShouldBeRemoved, char[] str) {
            char[] copy = new char[str.length - 1];
            int indexOfCopy = 0;
            for (int i = 0; i < str.length; i++) {
                if (str[i] == charShouldBeRemoved) continue;
                copy[indexOfCopy++] = str[i];
            }
            return copy;
        }
    }

    public static void main(String[] args) throws Exception {
        ForkJoinPool forkJoinPool = new ForkJoinPool();

        long start = System.currentTimeMillis();
        Future<List<String>> results = forkJoinPool.submit(new PermutationsRecursiveTask("abcdefg".toCharArray()));
        int i = 1;
        for (String result : results.get()) {
            System.out.println(i++ + ": " + result);
        }
        System.out.println(System.currentTimeMillis() - start);
    }
}
